from abc import ABC, ABCMeta, abstractmethod

# https://zhuanlan.zhihu.com/p/508700685


def my_decorator(func):
    def wrapper(*args, **kwargs):
        print(f"Decorator {func.__name__} called")
        return func(*args, **kwargs)

    return wrapper


class C1(ABC):
    def __init__(self):
        methods = list(filter(lambda m: not m.startswith('__') and callable(getattr(self, m)), dir(self)))
        print(methods)
        self.decorate_methods(methods)

    @classmethod
    def decorate_methods(cls, method_names):
        for name in method_names:
            setattr(cls, name, my_decorator(getattr(cls, name)))
        return cls

    @abstractmethod
    def fun(self):
        print('this is C1 func')

    def fun1(self):
        ...


class C2(C1):
    def __init__(self):
        super(C2, self).__init__()
        self._val = None

    def fun(self):
        print('this is C2 func')
        super().fun()

    def fun2(self):
        ...

    # @property
    # def val(self):
    #     return self._val
    #
    # @val.setter
    # def val(self, val):
    #     self._val = val


if __name__ == '__main__':
    c = C2()
    c.fun()
    c.fun2()
    c.fun1()
    # print(c.val)

    # c1 = C1()
